package bavaria.hightech.banking.accounts;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import bavaria.hightech.banking.bank.StringBuilderOutputStream;
import bavaria.hightech.banking.exceptions.FixedDepositException;
import bavaria.hightech.banking.lists.Booking;
import bavaria.hightech.banking.money.Currency.currencyEnum;
import bavaria.hightech.banking.money.Money;
import bavaria.hightech.banking.resourceBundles.LanguageBundle;
import bavaria.hightech.banking.statement.KtoAuszugsDienst;
import bavaria.hightech.banking.time.TimeServer;

/**
 * abstract base class account
 * 
 * @author Dietmar
 */
public abstract class Account {

	private final int accNr;
	private final String depositor;
	protected final Money money;
	protected final Calendar creationTimeStamp;
	private final List<Booking> myBookingsList = new Vector<Booking>(); // nachdenken-austauschbarkeit
	public LanguageBundle languageBundle;

	/**
	 * default-constructor
	 * @param accNr
	 * @param depositor
	 * @param currency
	 */
	public Account(int accNr, String depositor, currencyEnum currency) {
		creationTimeStamp = TimeServer.getCalendar();
		this.accNr = accNr;
		this.depositor = depositor;
		this.money = new Money(currency);
	}

	/**
	 * draws money from the money object and books it
	 * 
	 * @param amount
	 * @param reason
	 * @throws FixedDepositException
	 */
	public boolean drawAmount(currencyEnum currency, long amount, String reason)
			throws FixedDepositException {
		money.drawAmount(currency, new BigInteger("" + amount));
		bookIt(-amount, reason);
		return true;
	}

	/**
	 * adds money to the money object and books it
	 * 
	 * @param amount
	 * @param reason
	 */
	public void addAmount(currencyEnum currency, long amount, String reason) {
		money.addAmount(currency, new BigInteger("" + amount));
		bookIt(amount, reason);
	}

	/**
	 * draws amount of money and books it
	 * 
	 * @param amount
	 * @param reason
	 */
	private void bookIt(long amount, String reason) {
		myBookingsList.add(new Booking(amount, reason));
	}

	/**
	 * applies an set of interest
	 * 
	 * @throws FixedDepositException
	 */
	public abstract void applyInterest() throws FixedDepositException;

	/**
	 * returns full account number
	 * 
	 * @return account number
	 */
	public int getAccountNumber() {
		return accNr;
	}

	/**
	 * get depositor as string
	 * 
	 * @return depositor
	 */
	public String getDepositor() {
		return depositor;
	}

	/**
	 * get balance
	 * 
	 * @return
	 */
	public long getBalance() {
		return money.getBalance();
	}

	/**
	 * iterates over the bookings list and returns a sorted, custom formatted
	 * string
	 * 
	 * @param mimeType
	 *            the mimeType for the formatted statement
	 * @param comparator
	 *            needs a comparator<Booking> as this function always returns a
	 *            sorted string
	 * @throws IOException
	 */
	public void getStatement(String mimeType, Comparator<Booking> comparator,
			StringBuilderOutputStream stream) throws IOException {
		Collections.sort(myBookingsList, comparator);
		KtoAuszugsDienst ktoAuszugsDienst = new KtoAuszugsDienst(this);
		ktoAuszugsDienst.getStatement(accNr, stream, mimeType);
	}

	/**
	 * returns the iterator of the bookingsList. Needed for Statement Service
	 */
	public Iterator<Booking> getBookingsListIterator() {
		return myBookingsList.iterator();
	}

	/**
	 * get the currency
	 * @return
	 */
	public String getCurrency() {
		return money.act_currency.toString();
	}

}
